library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity datapath is
    port(
    MemToReg, MemWrite, Branch, AluSrc, RegDst, RegWrite, Jump: in std_logic;
    AluControl: in std_logic_vector(2 downto 0);
    reset, clk, dump: in std_logic;
    pc, instr: out std_logic_vector(31 downto 0)
    );
end datapath;

architecture behav of datapath is
    component flopr
        generic(n: integer);
        port(
        d : in std_logic_vector(n downto 0);
        clk, rst: in std_logic;
        q : out std_logic_vector(n downto 0)
        );
    end component;

    component mux2
        generic(n: integer);
        port(
        d0, d1: in std_logic_vector(n downto 0);
        s: in std_logic;
        y: out std_logic_vector(n downto 0)
        );
    end component;

    component signext
        port(
        a: in std_logic_vector(15 downto 0);
        y: out std_logic_vector(31 downto 0)
        );
    end component;

    component alu
    port(
    a, b: in std_logic_vector(31 downto 0);
    alucontrol: in std_logic_vector(2 downto 0);
    result: out std_logic_vector(31 downto 0);
    zero: out std_logic
    );
    end component;

    component imem
        port(
        a: in std_logic_vector(31 downto 0);
        rd: out std_logic_vector(31 downto 0)
        );
    end component;

    component dmem is
    port(a, wd: in std_logic_vector(31 downto 0);
        clk, we, dump: in std_logic;
        rd: out std_logic_vector(31 downto 0)
        );
    end component;

    component regfile is
        port(
        ra1, ra2, wa3: in std_logic_vector(4 downto 0);
        wd3: in std_logic_vector(31 downto 0);
        clk, we: in std_logic;
        rd1, rd2: out std_logic_vector(31 downto 0)
        );
    end component;

    signal PCPlus4, PCBranch, PCNext, PCJump, PCp, PC_s, instr_s, Result, SrcA,
           WriteData, SignImm, SrcB, ALUResult, Sl2Out, ReadData:
           std_logic_vector(31 downto 0);
    signal WriteReg: std_logic_vector(4 downto 0);
    signal PCSrc, Zero: std_logic;

begin
    IF_mux2_0: mux2
        generic map(31)
        port map(PCPlus4, PCBranch, PCSrc, PCNext);

    IF_mux2_1: mux2
        generic map(31)
        port map(PCNext, PCJump, Jump, PCp);

    IF_flopr: flopr
        generic map(31)
        port map(PCp, clk, reset, PC_s);

    IF_imem: imem
        port map(PC_s, instr_s);

    PCJump <= PCPlus4(31 downto 28) & instr_s(25 downto 0) & "00";
    PCSrc <= Branch and Zero;
    PCPlus4 <= PC_s + conv_std_logic_vector(4, 32);

    ID_regfile: regfile
        port map(instr_s(25 downto 21), instr_s(20 downto 16),
                 WriteReg, Result, clk, RegWrite, SrcA, WriteData);

    ID_signext: signext
        port map(instr_s(15 downto 0), SignImm);

    EX_alu: alu
        port map(SrcA, SrcB, AluControl, ALUResult, Zero);

    EX_mux2_0: mux2
        generic map(31)
        port map(WriteData, SignImm, AluSrc, SrcB);

    EX_mux2_1: mux2
        generic map(4)
        port map(instr_s(20 downto 16), instr_s(15 downto 11), RegDst, WriteReg);

    Sl2Out <= shl(SignImm, conv_std_logic_vector(2, 32));
    PCBranch <= Sl2Out + PCPlus4;

    MEM_dmem: dmem
        port map(ALUResult, WriteData, clk, MemWrite, dump, ReadData);

    WB_mux0: mux2
        generic map(31)
        port map(ALUResult, ReadData, MemToReg, Result);

    instr <= instr_s;
    pc <= PC_s;
end behav;
